//*************************************************************************//
//*           _____   ____________            ______               __     *//
//*          / /__ \ / ____/ ____/           / ____/___  _________/ /     *//
//*     __  / /__/ // __/ / __/    ______   / /_  / __ \/ ___/ __  /      *//
//*    / /_/ // __// /___/ /___   /_____/  / __/ / /_/ / /  / /_/ /       *//
//*    \____//____/_____/_____/           /_/    \____/_/   \__,_/        *//
//*                                                                       *//
//*     Copyright (c) 2006 Ford Argentina. All Rights Reserved.           *//
//*                                                                       *//
//*************************************************************************//

package ar.com.ford.it.webengine.struts;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.util.MessageResources;
import ar.com.ford.it.webengine.metric.MetricManager;
import ar.com.ford.it.webengine.websession.WebSession;
import com.ford.it.logging.ILogger;
import com.ford.it.logging.Level;
import com.ford.it.logging.LogFactory;


/**
 * DispatcherMethodAction <br>
 * 
 * Action que invoca al metodo que se haya configurado en el parametro
 * <b>parameter</b> del archivo <code>struts-config.xml</code>.
 * Si no se lo especifica, se invoca al metodo <b>initPage</b>
 * <br>
 * <br>
 * Los metodos <b>isTokenValid</b> y <b>resetToken</b> permiten verificar la
 * sincronizacion del action con el TokenProcessor de Ford.
 * 
 * @author Aji
 */
public abstract class DispatcherMethodAction extends Action {


    private static final String CLASS_NAME = DispatcherMethodAction.class.getName();
    private static final ILogger log = LogFactory.getInstance().getLogger(CLASS_NAME);

	/**
	 * TokenProcessor de Ford
	 */
    private static TokenProcessor tokenProcessor = TokenProcessor.getInstance();

    protected Class clazz = this.getClass();
	protected static MessageResources messages = MessageResources.getMessageResources("org.apache.struts.actions.LocalStrings");	
	protected HashMap methods = new HashMap();
    protected Class types[] = {
					        FordActionMapping.class, ActionForm.class,
					        HttpServletRequest.class, HttpServletResponse.class, 
					        WebSession.class, ActionMessages.class, 
					        ActionMessages.class, ActionMessages.class 
				        };
	
	
	/**
	 * Method executeAction.
	 * @param fordmapping FordActionMapping
	 * @param form ActionForm
	 * @param request Request
	 * @param response Response
	 * @param websession Sesion interna
	 * @param msgs Mensajes de status
	 * @param warns Mensajes de advertencia
	 * @param errormsgs Mensajes de error
	 * @return ActionForward
	 * @throws Exception
	 */
    public ActionForward executeAction(FordActionMapping fordmapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, WebSession websession, ActionMessages msgs, ActionMessages warns, ActionMessages errormsgs) throws Exception {
		String METHOD_NAME = "executeAction";
		log.entering(CLASS_NAME, METHOD_NAME);
		
		ActionForward result;
   
		String parameter = fordmapping.getParameter();
        if (parameter == null) {
            parameter = "initPage";
        }

		
        result = dispatchMethod(fordmapping, form, request, response, parameter, websession, msgs, warns, errormsgs);    

		log.exiting(CLASS_NAME, METHOD_NAME);
        return result;
    
    }



	/**
	 * Invocar el metodo que se pase en el parametro <b>name</b>
	 * @param mapping FordActionMapping
	 * @param form ActionForm
	 * @param request Request
	 * @param response Response
	 * @param name Metodo a invocar
	 * @param websession Sesion interna
	 * @param msgs Mensajes de status
	 * @param warns Mensajes de advertencia
	 * @param errormsgs Mensajes de error
	 * @return ActionForward 
	 * @throws Exception
	 */
	protected ActionForward dispatchMethod(FordActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String name, WebSession websession, ActionMessages msgs, ActionMessages warns, ActionMessages errormsgs) throws Exception {
		String METHOD_NAME = "dispatchMethod";                                                

		log.entering(CLASS_NAME, METHOD_NAME);

        if (name == null) {
	        log.exiting(CLASS_NAME, METHOD_NAME);
            return unspecified(mapping, form, request, response, websession, msgs, warns, errormsgs);
        }

        Method method = null;
        try {
            method = getMethod(name);
        } 
        catch (NoSuchMethodException e) {
            String message = messages.getMessage("dispatch.method", mapping.getPath(), name);
            log.logp(Level.SEVERE, CLASS_NAME, METHOD_NAME, "NoSuchMethodException", e);		
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
	        log.exiting(CLASS_NAME, METHOD_NAME);
            return (null);
        }

        ActionForward forward = null;
        try {
            Object args[] = { mapping, form, request, response, websession, msgs, warns, errormsgs };
            MetricManager.startMetric(mapping.getPath()+" "+name, websession.getUser().getId());
            forward = (ActionForward) method.invoke(this, args);
            MetricManager.endMetric();            
        } 
        catch (ClassCastException e) {
            String message = messages.getMessage("dispatch.return", mapping.getPath(), name);
            log.logp(Level.SEVERE, CLASS_NAME, METHOD_NAME, "ClassCastException", e);
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
	        log.exiting(CLASS_NAME, METHOD_NAME);
            return (null);
        } 
        catch (IllegalAccessException e) {
            String message = messages.getMessage("dispatch.error", mapping.getPath(), name);
            log.logp(Level.SEVERE, CLASS_NAME, METHOD_NAME, "IllegalAccessException", e);
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
	        log.exiting(CLASS_NAME, METHOD_NAME);
            return (null);
        } 
        catch (InvocationTargetException e) {
            Throwable t = e.getTargetException();
            if (t instanceof Exception) {
                throw ((Exception) t);
            } 
            else {
                String message = messages.getMessage("dispatch.error", mapping.getPath(), name);
                log.logp(Level.SEVERE, CLASS_NAME, METHOD_NAME, "InvocationTargetException", e);
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
		        log.exiting(CLASS_NAME, METHOD_NAME);
                return (null);
            }
        }


        log.exiting(CLASS_NAME, METHOD_NAME);
        return (forward);
    }



	/**
	 * Method unspecified.
	 * @param mapping FordActionMapping
	 * @param form ActionForm
	 * @param request Request
	 * @param response Response
	 * @param websession Sesion interna
	 * @param msgs Mensajes de status
	 * @param warns Mensajes de advertencia
	 * @param errormsgs Mensajes de error
	 * @return ActionForward
	 * @throws Exception
	 */
	protected ActionForward unspecified(FordActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, WebSession websession, ActionMessages msgs, ActionMessages warns, ActionMessages errormsgs) throws Exception {
		String METHOD_NAME = "unspecified";
		log.entering(CLASS_NAME, METHOD_NAME);
		
        String message = messages.getMessage("dispatch.parameter", mapping.getPath(), mapping.getParameter());

        log.logp(Level.SEVERE, CLASS_NAME, METHOD_NAME, message);
        response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
        log.exiting(CLASS_NAME, METHOD_NAME);
        return (null);

    }


    /**
     * Verifica si existe un metodo con el nombre especificado y que la
     * parametrizacion del mismo se corresponda con la definida en types
     *
     * @param name Nombre del metodo a ser invocado
     *
     * @exception NoSuchMethodException Si el metodo no se encontro
     */
    protected Method getMethod(String name) throws NoSuchMethodException {

        synchronized (methods) {
            Method method = (Method) methods.get(name);
            if (method == null) {
                method = clazz.getMethod(name, types);
                methods.put(name, method);
            }
            return (method);
        }

    }

	/* (non-Javadoc)
	 * @see org.apache.struts.action.Action#isTokenValid(HttpServletRequest)
	 */
    public boolean isTokenValid(HttpServletRequest request, FordActionMapping fordmapping){
        return tokenProcessor.isTokenValid(request, fordmapping.getPath());
    }

	/* (non-Javadoc)
	 * @see org.apache.struts.action.Action#isTokenValid(HttpServletRequest, boolean)
	 */
    public boolean isTokenValid(HttpServletRequest request, boolean resetToken, FordActionMapping fordmapping){
        return tokenProcessor.isTokenValid(request, fordmapping.getPath(), resetToken);
    }

	/* (non-Javadoc)
	 * @see org.apache.struts.action.Action#resetToken(HttpServletRequest)
	 */
    public void resetToken(HttpServletRequest request, FordActionMapping fordmapping){
        tokenProcessor.resetToken(request, fordmapping.getPath());
    }
    


	/**
	 * Metodo que se invoca cuando no se configura el parametro <b>parameter</b>
	 * en el FordActionMapping
	 * @param mapping FordActionMapping
	 * @param form ActionForm
	 * @param request Request
	 * @param response Response
	 * @param websession Sesion interna
	 * @param msgs Mensajes de status
	 * @param warns Mensajes de advertencia
	 * @param errormsgs Mensajes de error
	 * @return ActionForward
	 */
	public abstract ActionForward initPage(FordActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, WebSession websession, ActionMessages msgs, ActionMessages warns, ActionMessages errormsgs);

}
